﻿namespace StockSharp.Algo.Indicators.Trend
{
	using System.ComponentModel;
	using System.Linq;
    using System;

	/// <summary>
	/// Адаптивная скользящая средняя Кауфманна.
	/// </summary>
	[DisplayName("KAMA")]
	[Description("Адаптивная скользящая средняя Кауфманна.")]
	public class KaufmannAdaptiveMovingAverage : LengthIndicator<decimal>
	{

		/// <summary>
		/// Создать <see cref="KaufmannAdaptiveMovingAverage"/>.
		/// </summary>
		public KaufmannAdaptiveMovingAverage()
			: base(typeof(decimal))
		{
            FastSCPeriod = 2;
            SlowSCPeriod = 30;
		}

		/// <summary>
		/// Сбросить состояние индикатора на первоначальное. Метод вызывается каждый раз, когда меняются первоначальные настройки (например, длина периода).
		/// </summary>
		public override void Reset()
		{
			base.Reset();
		}

        /// <summary>
        /// Период "быстрой" EMA. Значение по умолчанию 2.
        /// </summary>
        public int FastSCPeriod { get; set; }

        /// <summary>
        /// Период "медленной" EMA. Значение по умолчанию 30.
        /// </summary>
        public int SlowSCPeriod { get; set; }

        /// <summary>
        /// Сформирован ли индикатор.
        /// </summary>
        public override bool IsFormed { get { return Buffer.Count > Length; } }

		/// <summary>
		/// Обработать входное значение.
		/// </summary>
		/// <param name="input">Входное значение.</param>
		/// <returns>Результирующее значение.</returns>
		protected override decimal OnProcess(IIndicatorValue input)
		{
            var newValue = input.GetValue<decimal>();
            Buffer.Add(newValue);

            if (!IsFormed)
            {
                return this.GetValue<decimal>(0);
            }

			if (Buffer.Count == Length + 1)
			{
				// Начальное значение - последнее входное значение.
				return newValue;
			}
			else
			{
				Buffer.RemoveAt(0);

                decimal direction = newValue - Buffer[0];

                decimal volatility = 0;

                for (int i = 1; i < Buffer.Count; i++)
                {
                    volatility += Math.Abs(Buffer[i] - Buffer[i - 1]);
                }

                volatility = volatility > 0 ? volatility : 0.00001m;

                decimal er = Math.Abs(direction / volatility);

                decimal fastSC = 2m / (FastSCPeriod + 1m);
                decimal slowSC = 2m / (SlowSCPeriod + 1m);

                decimal ssc = er * (fastSC - slowSC) + slowSC;
                decimal smooth = (ssc * ssc);

				return (newValue - this.GetValue<decimal>(0)) * smooth + this.GetValue<decimal>(0);
			}
		}
	}
}